/* File: ast_decl.h
 * ----------------
 * In our parse tree, Decl nodes are used to represent and
 * manage declarations. There are 4 subclasses of the base class,
 * specialized for declarations of variables, functions, classes,
 * and interfaces.
 *
 * pp3: You will need to extend the Decl classes to implement 
 * semantic processing including detection of declaration conflicts 
 * and managing scoping issues.
 */

#ifndef _H_ast_decl
#define _H_ast_decl

#include "ast.h"
#include "list.h"
#include "ast_type.h"

class Type;
class NamedType;
class Identifier;
class Stmt;
class Scope;

class Decl : public Node 
{
protected:
   Identifier *id;
   Scope *scope;
   
public:
   Decl(Identifier *name);
   friend ostream& operator<<(ostream& out, Decl *d) { return out << d->id; }
   const char* getName() { 
      return id->getName();
   }
   Identifier *getId() { 
      printf("cor dump");
      return id;
   }
   virtual void check() = 0;
   Scope *getScope() { return scope; }
   virtual void useScope(Scope *s);
   virtual bool equals(Decl *d) {return true;}
};

class VarDecl : public Decl 
{
protected:
   Type *type;
   
public:
   VarDecl(Identifier *name, Type *type);
   void check();
   Type *getType() { return type; }
   bool equals(Decl *d); 
   
};

class ClassDecl : public Decl 
{
protected:
   List<Decl*> *members;
   NamedType *extends;
   List<NamedType*> *implements;
   
public:
   ClassDecl(Identifier *name, NamedType *extends, 
             List<NamedType*> *implements, List<Decl*> *members);
   List<NamedType*>* getImplements() { return implements; }
   void useScope(Scope *s);
   void checkMembersImplemented(NamedType *t);
   void checkMembersExtended(NamedType *t);
   void checkExtendsDefined();
   void checkImplementsDefined();
   void checkScope(Scope *s);
   void checkInterfacesImplemented();
   NamedType *getType() { return new NamedType(id); }
   void check();
   NamedType *getExtends() { return extends; }
   bool equals(Decl *d) {return true;} 
   
};

class InterfaceDecl : public Decl 
{
protected:
   List<Decl*> *members;
   
public:
   InterfaceDecl(Identifier *name, List<Decl*> *members);
   void check();
   Type *getType() { return new NamedType(id); }
   void useScope(Scope *s);
   List<Decl*>* getMembers() { return members; }
   bool equals(Decl *d) {return true;} 
};

class FnDecl : public Decl 
{
protected:
   List<VarDecl*> *formals;
   Type *returnType;
   Stmt *body;
   
public:
   FnDecl(Identifier *name, Type *returnType, List<VarDecl*> *formals);
   void SetFunctionBody(Stmt *b);
   Type *getReturnType() { return returnType; }
   void useScope(Scope *s);
   List<VarDecl*>* getFormals() { return formals; }
   void check();
   bool equals(Decl *d);
};

#endif
